View Javadoc

1   /*
2   Karma KarmaConsole - Command Line Interface for the Karma application
3   Copyright (C) 2004  Toolforge <www.toolforge.nl>
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19  package nl.toolforge.karma.console;
20  
21  import nl.toolforge.karma.cli.cmd.ConsoleCommandResponseHandler;
22  import nl.toolforge.karma.core.ErrorCode;
23  import nl.toolforge.karma.core.boot.WorkingContext;
24  import nl.toolforge.karma.core.boot.WorkingContextConfiguration;
25  import nl.toolforge.karma.core.boot.WorkingContextException;
26  import nl.toolforge.karma.core.bundle.BundleCache;
27  import nl.toolforge.karma.core.cmd.CommandContext;
28  import nl.toolforge.karma.core.cmd.CommandException;
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  import java.io.BufferedReader;
34  import java.io.File;
35  import java.io.IOException;
36  import java.io.InputStreamReader;
37  import java.util.Calendar;
38  import java.util.ResourceBundle;
39  import java.util.prefs.Preferences;
40  
41  /***
42   * <p>The <code>KarmaConsole</code> is the command-line interface for Karma. The class presents a simple-to-use command-line
43   * terminal, where developers can type in their commands and if you're lucky, stuff works.
44   *
45   * <p>Haven't fully tested it, but should be 'singleton'.
46   *
47   * @author D.A. Smedes
48   *
49   * @version $Id: KarmaConsole.java,v 1.23 2005/07/11 04:37:49 clutjespelberg Exp $
50   */
51  public final class KarmaConsole {
52  
53    // Logging system should be initialized by now ...
54    //
55    private Log logger = LogFactory.getLog(KarmaConsole.class);
56  
57    private final ResourceBundle FRONTEND_MESSAGES = BundleCache.getInstance().getBundle(BundleCache.FRONTEND_MESSAGES_KEY);
58  
59    private String lastLine = "";
60    private boolean immediate = true;
61    private CommandContext commandContext = null;
62  
63    public KarmaConsole() {}
64  
65  
66    /***
67     *
68     * @param args  The working context (0), whether to update (1) and the command
69     *              plus his options (3 ...).
70     */
71    public void runConsole(String[] args) {
72  
73      Runtime.getRuntime().addShutdownHook(new Thread() {
74  
75        public void run() {
76  
77          if (immediate) {
78  
79            String text = FRONTEND_MESSAGES.getString("message.THANK_YOU");
80            int length = text.length();
81  
82            writeln("\n");
83  
84            writeln(FRONTEND_MESSAGES.getString("message.EXIT"));
85  
86            StringBuffer g = new StringBuffer();
87            g.append("\n\n").append(StringUtils.repeat("*", length));
88            g.append("\n").append(text).append("\n");
89            g.append(StringUtils.repeat("*", length)).append("\n");
90  
91            writeln(g.toString());
92          }
93        }
94      });
95  
96      // If the '-w <working-context> option is used, use it.
97      //
98      WorkingContext workingContext;
99      if ( args[0] == null || args[0].equals("") ) {
100       workingContext = new WorkingContext(Preferences.userRoot().get(WorkingContext.WORKING_CONTEXT_PREFERENCE, WorkingContext.DEFAULT));
101     } else {
102       workingContext = new WorkingContext(args[0]);
103     }
104 
105     writeln(
106         "\n" +
107         "      _________________________________\n" +
108         "      Welcome to Karma (R1.0 RC1) !!!!!\n" +
109         "\n" +
110         "      K     A     R        M        A\n" +
111         "      .     .     .        .        .\n" +
112         "      Karma Ain't Remotely Maven or Ant\n" +
113         "      _________________________________\n"
114     );
115 
116     String karmaHome = System.getProperty("karma.home");
117     if (karmaHome == null) {
118       writeln("[ console ] Property 'karma.home' not set; logging will be written to " + System.getProperty("user.home") + File.separator + "logs.");
119     } else {
120       writeln("[ console ] Logging will be written to " + System.getProperty("karma.home") + File.separator + "logs.");
121     }
122 
123     writeln("[ console ] Checking working context configuration for `" + workingContext.getName() + "`.");
124 
125     WorkingContextConfiguration configuration = null;
126 
127     try {
128       configuration = new WorkingContextConfiguration(workingContext);
129       try {
130         configuration.load();
131       } catch (WorkingContextException e) {}
132 
133       workingContext.configure(configuration);
134 
135       // Check the validity state of the configuration.
136       //
137 
138       ErrorCode error = configuration.check();
139       ErrorCode error2 = null;
140       ErrorCode error3 = null;
141 
142       if (error != null) {
143         writeln("[ console ] ** Error in working context configuration : " + error.getErrorMessage());
144       }
145       if (configuration.getManifestStore() == null) {
146         writeln("[ console ] ** Error in working context configuration : Missing configuration for manifest store.");
147       } else {
148         error2 = configuration.getManifestStore().checkConfiguration();
149         if (error2 != null) {
150           writeln("[ console ] ** Error in working context configuration : " + error2.getErrorMessage());
151         }
152       }
153       if (configuration.getLocationStore() == null) {
154         writeln("[ console ] ** Error in working context configuration : Missing configuration for location store.");
155       } else {
156         error3 = configuration.getLocationStore().checkConfiguration();
157         if (error3 != null) {
158           writeln("[ console ] ** Error in working context configuration : " + error3.getErrorMessage());
159         }
160       }
161 
162       while (error != null || configuration.getManifestStore() == null || error2 != null || configuration.getLocationStore() == null || error3 != null ) {
163 
164         // todo hier eerst de foutmelding tonen.
165 
166         // todo offline-mode ?
167 
168         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
169 
170         String start = "";
171         try {
172           while (!start.matches("n|y")) {
173             write("[ console ] Working context not initialized properly, start configurator ? [Y|N] (Y) :");
174             start = (reader.readLine().trim()).toLowerCase();
175             start = ("".equals(start) ? "y" : start);
176           }
177         } catch (IOException e) {
178           start = "n";
179         }
180 
181         if ("n".equals(start)) {
182           writeln("[ console ] ** Configuration incomplete. Cannot start Karma.");
183           writeln("[ console ] Check configuration manually.");
184 
185           System.exit(1);
186 
187         } else {
188           Configurator configurator = new Configurator(workingContext, configuration);
189           configurator.checkConfiguration();
190 
191           // Run checks once more.
192           //
193           error = configuration.check();
194           if (configuration.getManifestStore() != null) {
195             error2 = configuration.getManifestStore().checkConfiguration();
196           }
197           if (configuration.getLocationStore() != null) {
198             error3 = configuration.getLocationStore().checkConfiguration();
199           }
200         }
201       }
202 
203     } catch (RuntimeException r) {
204       writeln("\n");
205       if (logger.isDebugEnabled()) {
206         r.printStackTrace();
207       }
208       System.exit(1);
209     }
210 
211     writeln("[ console ] Configuration complete. Loading working context `" + workingContext.getName() + "` ...");
212 
213     // Right now, we have a valid configuration and continue to load the working context.
214     //
215     workingContext.configure(configuration);
216 
217     writeln("[ console ] Configuration can be manually updated in `" + workingContext.getWorkingContextConfigurationBaseDir() + "`");
218 
219     writeln("\n[ console ] Starting up console ...\n");
220 
221     //
222     //
223     commandContext = new CommandContext(workingContext);
224     try {
225 //      long start = System.currentTimeMillis();
226       commandContext.init(new ConsoleCommandResponseHandler(this), new Boolean(args[1]).booleanValue());
227 //      System.out.println("TOTAL STARTUP-TIME: " + (System.currentTimeMillis() - start));
228     } catch (CommandException e) {
229       logger.warn(e.getMessage());
230     }
231 
232     try {
233 
234       // Open a reader, which is the actual command line ...
235       //
236       BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
237 
238 
239       String line = null;
240       while (true) {
241 
242         prompt();
243 
244         if (reader != null || reader.readLine() != null) {
245           line = reader.readLine().trim();
246         }
247 
248         if ((line == null) || ("".equals(line.trim()))) {
249           prompt();
250           continue;
251         }
252 
253         if ("[A".equals(line)) {
254           line = lastLine;
255           writeln(line);
256         } else {
257           lastLine = line;
258         }
259 
260         try {
261           commandContext.execute(line);
262         } catch (CommandException e) {
263           // The command context has already sent all required messages.
264           //
265         }
266       }
267     } catch (Throwable e) {
268       writeln("\n");
269       logger.fatal("Exception caught by KarmaConsole catch-all. ", e);
270       
271       String logfile = System.getProperty("karma.home", System.getProperty("user.home")) + File.separator + "logs" + File.separator + "karma-default.log";
272       
273       System.out.println("Something went BOOM inside of Karma.");
274       System.out.println("Details: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName()));
275       System.out.println("See the log file (" + logfile + ") for more information.");
276       System.out.println("Please report recurring problems to the Karma developers (http://sourceforge.net/tracker/?group_id=98766).");
277       System.out.println("We apologize for the inconvenience.");
278       System.out.println();
279       
280       System.exit(1);
281     }
282   }
283 
284 
285   /***
286    * Gets the default prompt, constructed as follows : <code>HH:MM:SS [ Karma ]</code>
287    */
288   public String getPrompt() {
289 
290     Calendar now = Calendar.getInstance();
291 
292     String end = (commandContext.getCurrentManifest() == null ? "Karma" : commandContext.getCurrentManifest().getName());
293     end = commandContext.getWorkingContext().getName() + "::" + end;
294     return
295         StringUtils.leftPad("" + now.get(Calendar.HOUR_OF_DAY) , 2, "0") + ":" +
296         StringUtils.leftPad("" + now.get(Calendar.MINUTE) , 2, "0") + ":" +
297         StringUtils.leftPad("" + now.get(Calendar.SECOND) , 2, "0") + " [ " + end + " ] > ";
298   }
299 
300   public void writeln(String text) {
301     System.out.println(text);
302   }
303 
304   public void write(String text) {
305     System.out.print(text);
306   }
307 
308   public void prompt() {
309     System.out.print(getPrompt());
310   }
311 }